package com.hisense.ovcloud.common3.tools;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * WebClientUtils
 *
 * @author John Chen
 * @since 2020/12/23
 */
public class WebClientUtils {
    /**
     * 默认3分钟超时时间
     */
    private final static Duration DEFAULT_REQUEST_TIMEOUT = Duration.ofSeconds(5L);

    /**
     * 默认代理超时时间
     */
    private final static Long DEFAULT_PROXY_TIMEOUT_MILLIS = DEFAULT_REQUEST_TIMEOUT.toMillis();

    //region 生成WebClient.Builder的方法

    /**
     * [基础创建方法]
     * 给到一个带超时时间，带代理，并带有不校验任何SSL整数的WebClient
     * 注意，由于使用代理的，基本都是一次性使用，故默认对连接进行关闭后释放操作
     *
     * @param requestTimeOut        超时时间
     * @param compressionEnabled    开启压缩？默认关闭
     * @return 返回一个带超时时间和默认全局信任的SSL请求校验器{@link WebClient.Builder}
     */
    public static WebClient.Builder getWebClientBuilderWithSslTrust(
            Duration requestTimeOut,
            int maxConnectPoolSize,
            boolean compressionEnabled) {
        if (requestTimeOut == null) {
            requestTimeOut = DEFAULT_REQUEST_TIMEOUT;
        }

        return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient
                .create(
                        /*
                        这里使用ConnectionProvider.builder().build()进行构建
                        构建出的PooledConnectionProvider用于HttpClient的连接池
                        注意，不要使用HttpClient.create()方法，大批量调用会导致OOM的问题
                         */
                        ConnectionProvider.builder(UUID.randomUUID().toString())
                                .maxConnections(maxConnectPoolSize)
                                .maxIdleTime(Duration.ofSeconds(20))
                                .maxLifeTime(Duration.ofSeconds(60))
                                .pendingAcquireTimeout(Duration.ofSeconds(60))
                                .evictInBackground(Duration.ofSeconds(120)).build()
                )
                //这里注入了一个抛弃一切SSL认证的sslContext
//                .secure(sslContextSpec -> sslContextSpec.sslContext(SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)))
                .responseTimeout(requestTimeOut)
                .compress(compressionEnabled)
                //重新定向开启
                .followRedirect(true)

        )).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
    }


    //endregion

    /**
     * 将http相应中的Cookie转换为用于http请求中的cookie
     * 方法中仅进行简单转换，不会对Cookie有效期等进行判断
     *
     * @param responseCookie 需要被转换的cookie
     * @return 返回可以用于请求的Cookies
     */
    public static MultiValueMap<String, String> transformResponseCookiesToRequestCookies(MultiValueMap<String, ResponseCookie> responseCookie) {
        MultiValueMap<String, String> ret = new LinkedMultiValueMap<>();
        if (responseCookie == null || responseCookie.size() == 0) {
            return ret;
        }


        for (Map.Entry<String, List<ResponseCookie>> entity : responseCookie.entrySet()) {
            String key = entity.getKey();
            List<ResponseCookie> value = entity.getValue();
            int size = value.size();
            if (size == 0) {
                continue;
            }
            List<String> cookies = new ArrayList<>(size);
            for (ResponseCookie cookie : value) {
                cookies.add(cookie.getValue());
            }
            ret.addAll(key, cookies);
        }
        return ret;
    }
}
